package com.harvey.exampreparation.activity;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;

import android.os.Bundle;
import android.view.MenuItem;

import com.google.android.material.bottomnavigation.BottomNavigationView;
import com.harvey.exampreparation.R;
import com.harvey.exampreparation.fragment.FrameLayoutFragment;
import com.harvey.exampreparation.fragment.GridLayoutFragment;
import com.harvey.exampreparation.fragment.LinearLayoutFragment;
import com.harvey.exampreparation.fragment.RelativeLayoutFragment;

/**
 * 基础布局实例
 *   包含了 LinearLayout（线性布局）、RelativeLayout（相对布局）、GridLayout（网格布局）以及 FrameLayout（帧布局）
 *   布局部分主要在 XML 文件中实现, 对应的实例：
 *     线性布局实例 -> fragment_linear_layout.xml
 *     相对布局实例 -> fragment_relative_layout.xml
 *     网格布局实例 -> fragment_grid_layout.xml
 *     帧布局实例   -> fragment_frame_layout.xml
 *   在下面的 BaseLayoutActivity 类主要实现了通过底部导航栏进行 Fragment 的切换，其对应的 Fragment 实现在：
 *     线性布局碎片 -> fragment/LinearLayoutFragment
 *     相对布局碎片 -> fragment/RelativeLayoutFragment
 *     网格布局碎片 -> fragment/GridLayoutFragment
 *     帧布局碎片   -> fragment/FrameLayoutFragment
 */
public class BaseLayoutActivity extends AppCompatActivity implements BottomNavigationView.OnNavigationItemSelectedListener {

    /*
     * 1. 声明实现了的 Fragment 子类
     */
    private LinearLayoutFragment linearLayoutFragment;
    private RelativeLayoutFragment relativeLayoutFragment;
    private GridLayoutFragment gridLayoutFragment;
    private FrameLayoutFragment frameLayoutFragment;

    /*
     * 2. 声明 Material Design 中 BottomNavigationView（底部导航栏控件） 的控件对象
     */
    private BottomNavigationView bnavLayoutSwitch;

    /*
     * 3. 声明 Fragment 操作相关的实例对象
     */
    private FragmentManager fm;               // 本 Activity 的 Fragment 管理对象
    private Fragment currentFragment;         // 表示当前展示的 Fragment 实例是哪一个

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_base_layout);
        initFragment();
        initView();
    }

    /**
     *  4. 实例化各个 Fragment
     */
    private void initFragment() {
        linearLayoutFragment = new LinearLayoutFragment();
        relativeLayoutFragment = new RelativeLayoutFragment();
        gridLayoutFragment = new GridLayoutFragment();
        frameLayoutFragment = new FrameLayoutFragment();
    }

    /**
     * 5. 设定视图相关
     */
    private void initView() {
        // 5.1. 通过 findViewById 获取到底部导航栏控件的实例
        bnavLayoutSwitch = findViewById(R.id.bnav_layout_switch);
        // 5.2. 设置底部导航栏点击了选项之后的监听器，
        //      可以使用匿名内部类的方式实现，也可以像这里一样，在该 Activity 中实现
        //      BottomNavigationView.OnNavigationItemSelectedListener 这个接口
        //      接口方法实现 下跳至下一个方法 5.3 处
        bnavLayoutSwitch.setOnNavigationItemSelectedListener(this);

        // 5.4. 通过调用父类的 getSupportFragmentManager 方法，可以获取到本类的 FragmentManager 实例
        fm = getSupportFragmentManager();
        // 5.5. 通过调用 FragmentManager 的 beginTransaction 方法，即可开启一个事务
        FragmentTransaction ft = fm.beginTransaction();
        // 这里我们要做的就是把 LinearLayout 绑定到 id 为 layout_fragment_container 容器上去
        ft.add(R.id.layout_fragment_container, linearLayoutFragment);
        // 然后提交事务即可
        ft.commit();
        // 当然在这里还要维护一下表示 “当前所显示的 Fragment” 的变量
        currentFragment = linearLayoutFragment;
    }

    /**
     * 5.3. 实现 BottomNavigationView.OnNavigationItemSelectedListener 接口的方法
     *      这个方法主要处理底部导航栏被点击切换后要干的事情
     */
    @Override
    public boolean onNavigationItemSelected(@NonNull MenuItem item) {
        // 该方法有一个 MenuItem 类型的参数,
        // 可以利用该方法的 getItemId() 获取到当前选择的导航项的 ItemId
        // ps: ItemId 是在 res/menu/layout_switch.xml 中定义的哦~
        switch (item.getItemId()) {
            case R.id.item_linear_layout:
                // 进到这一项就是选中了 线性布局 的导航选项,
                // 这里要做的事情就是切换当前展示的 Fragment 为 LinearLayoutFragment
                // 我们这里实现一个 changeFragment 来完成这个操作, 具体为下面方法 第6步
                changeFragment(linearLayoutFragment);
                return true;
            case R.id.item_relative_layout:
                // 同上
                changeFragment(relativeLayoutFragment);
                return true;
            case R.id.item_grid_layout:
                // 同上
                changeFragment(gridLayoutFragment);
                return true;
            case R.id.item_frame_layout:
                // 同上
                changeFragment(frameLayoutFragment);
                return true;
        }

        return false;
    }

    /**
     * 6. 这里实现以下切换 Fragment 的方法
     *    除了这里的实现方法，还有一种方法是直接使用 replace, 只需要一行：
     *      fm.beginTransaction().replace(R.id.layout_fragment_container, dist).commit();
     *    但是这种方法有一个很大的缺点就是每一次切换 replace 会摧毁 Fragment 再新建目标 Fragment, 十分消耗资源
     *    下面这种实现方法是谷歌推荐的一种做法
     */
    private void changeFragment(Fragment dist) {
        // 先判断点击的是否为当前显示的 Fragment
        if (currentFragment != dist) {
            // 确定不是当前显示的 Fragment 后，就可以开启一个事务了
            FragmentTransaction ft = fm.beginTransaction();
            // 通过调用目标 Fragment 的 isAdded 方法，判断是否以及添加过
            if (!dist.isAdded()) {
                // 若没有添加过该 Fragment, 首先先把当前 Fragment 隐藏, 再进行添加操作
                ft.hide(currentFragment)
                        .add(R.id.layout_fragment_container, dist)
                        .commit();
            } else {
                // 若添加过，则把当前 Fragment 隐藏掉，再把已经隐藏的目标 Fragment 再 show 出来
                ft.hide(currentFragment)
                        .show(dist)
                        .commit();
            }
            // 记得还要维护以下当前显示的 Fragment
            currentFragment = dist;
        }
    }
}